/*************************************************************
 * Title: 
 * Description: 
 * Author: Snow Huang
 * Email: Shaobin.Software@gmail.com Shaobin_Software@163.com
 * CreateTime: Aug 24, 2010 2:31:05 PM
 * Copyright © 落羽社区 All right reserved
 ************************************************************/
package snow.core.util.algorithm.tree;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.springframework.util.Assert;

import snow.core.util.toolkit.CollectionHelper;

/**
 * 
 */
public abstract class BaseTree<T extends BaseTree<T>> implements Tree<T> {

	private final Class<T> treeClass;

	private String name;
	private String code;
	private String comments;

	private T parent;

	private Set<T> children = new HashSet<T>();

	protected BaseTree(Class<T> treeClass) {
		Assert.notNull(treeClass, "");
		this.treeClass = treeClass;
	}

	/**
	 * 添加指定节点为其子节点
	 * 
	 * @param tree
	 *            指定节点
	 * @see snow.core.util.algorithm.tree.Tree#addChild(snow.core.util.algorithm.tree.Tree)
	 */
	public void addChild(T tree) {
		// 1.判断是否为空
		Assert.notNull(tree, "");
		// 2.判断是否为自身节点
		Assert.isTrue(equals(tree), "");
		// 3.判断是否已经为该节点的子节点
		if (children.contains(tree)) {
			return;
		}
		// 4.判断指定节点是否为该节点的父节点
		Assert.isTrue(isChildOf(tree), "");
	}

	/**
	 * @param obj
	 * @return
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Object obj) {
		// 1.判断两个对象的内存地址是否一样
		if (this == obj) {
			return true;
		}
		// 2.判断指定对象是否为空并且是否为该节点的实例
		if (obj == null || !treeClass.isAssignableFrom(obj.getClass())) {
			return false;
		}
		// 3.强制转型,经过以上判断，这一步是安全的
		T another = treeClass.cast(obj);
		// 4.验证两棵树是否相等
		return ObjectUtils.equals(getName(), another.getName()) && ObjectUtils.equals(getParent(), another.getParent());
	}

	/**
	 * @return 递归来获取所有子节点
	 * @see snow.core.util.algorithm.tree.Tree#getAllChildren()
	 */
	public Set<T> getAllChildren() {
		// 1.判断是否为叶子节点,是则返回空集合
		if (isLeaf()) {
			return Collections.emptySet();
		}
		// 2.将子节点置入集合中
		Set<T> allChildren = new HashSet<T>(children);
		// 3.遍历所有的子节点,将子节点的所有子节点置入集合中,此处为递归调用
		for (T child : allChildren) {
			allChildren.addAll(child.getAllChildren());
		}
		return allChildren;
	}

	/**
	 * @return 递归获取所有子节点中的叶子节点
	 * @see snow.core.util.algorithm.tree.Tree#getAllLeaves()
	 */
	public Set<T> getAllLeaves() {
		// 1.新建一个集合对象
		Set<T> allLeaves = new HashSet<T>();
		// 2.判断是否为叶子节点,如果是则将本节点加入到集合中
		if (isLeaf()) {
			allLeaves.add(getThisTree());
		} else {
			// 3.遍历所有子节点,将子节点的所有叶子节点添加到集合中,此处为递归调用
			for (T child : children) {
				allLeaves.addAll(child.getAllLeaves());
			}
		}
		return allLeaves;
	}

	/**
	 * @return 获取直属子节点
	 * @see snow.core.util.algorithm.tree.Tree#getChildren()
	 */
	public Set<T> getChildren() {
		return CollectionHelper.getNewSetFrom(children);
	}

	/**
	 * @return 代码
	 * @see snow.core.util.algorithm.tree.Tree#getCode()
	 */
	public String getCode() {
		return code;
	}

	/**
	 * @return 其他描述
	 * @see snow.core.util.algorithm.tree.Tree#getComments()
	 */
	public String getComments() {
		return comments;
	}

	/**
	 * @return 名称
	 * @see snow.core.util.algorithm.tree.Tree#getName()
	 */
	public String getName() {
		return name;
	}

	/**
	 * @return 父节点
	 * @see snow.core.util.algorithm.tree.Tree#getParent()
	 */
	public T getParent() {
		return parent;
	}

	protected T getThisTree() {
		return treeClass.cast(this);
	}

	/**
	 * @return
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		return new HashCodeBuilder().append(getName()).append(getParent()).toHashCode();
	}

	/**
	 * @param tree
	 *            指定节点
	 * @return 是否为指定节点的子节点
	 * @see snow.core.util.algorithm.tree.Tree#isChildOf(snow.core.util.algorithm.tree.Tree)
	 */
	public boolean isChildOf(T tree) {
		return !(equals(tree) || isParentOf(tree));
	}

	/**
	 * @return 是否为叶子节点
	 * @see snow.core.util.algorithm.tree.Tree#isLeaf()
	 */
	public boolean isLeaf() {
		return CollectionUtils.isEmpty(children);
	}

	/**
	 * @param tree
	 *            指定节点
	 * @return 是否为指定节点的父节点
	 * @see snow.core.util.algorithm.tree.Tree#isParentOf(snow.core.util.algorithm.tree.Tree)
	 */
	public boolean isParentOf(T tree) {
		// 1.判断是否为叶子节点或者指定节点是否为null值,如果是则返回false
		if (isLeaf() || tree == null) {
			return false;
		}
		// 2.判断是否为直属下级节点,如果是则返回true
		if (children.contains(tree)) {
			return true;
		}
		// 3.递归调用直属下级节点判断是否为指定节点的父节点
		for (T child : children) {
			if (child.isParentOf(tree)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @return 是否为根节点
	 */
	public boolean isRoot() {
		return getParent() == null;
	}

	/**
	 * 删除指定节点
	 * 
	 * @param tree
	 *            指定节点
	 * @see snow.core.util.algorithm.tree.Tree#removeChild(snow.core.util.algorithm.tree.Tree)
	 */
	public void removeChild(T tree) {
		children.remove(tree);
	}

	/**
	 * @param code
	 *            the code to set
	 */
	public void setCode(String code) {
		this.code = code;
	}

	/**
	 * @param comments
	 *            the comments to set
	 */
	public void setComments(String comments) {
		this.comments = comments;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * 设置父节点为指定节点
	 * 
	 * @param parent
	 *            指定节点
	 * @return 是否设置成功
	 * @see snow.core.util.algorithm.tree.Tree#setParent(snow.core.util.algorithm.tree.Tree)
	 */
	public void setParent(T parent) {
		// 1.如果指定节点为null值,则将该节点设置成根节点
		if (parent == null) {
			this.parent = parent;
			return;
		}
		// 2.判断指定节点是否为该节点本身,如果是则抛出异常
		Assert.isTrue(!equals(parent), "");
		// 3.判断指定节点是否为该节点的下级节点,如果是则抛出异常
		Assert.isTrue(isParentOf(parent), "");
		this.parent = parent;
	}
}
